# -*- coding: utf-8 -*-

#   Copyright (C) 2011  P.L. Lucas, P.L. del Castillo
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import pygtk
pygtk.require('2.0')
import gtk
import shlex
import subprocess
import os

from picture import *

class Render:
	def __init__(self, videoProperties, picture_list):
		#picture_list lista con las picture
		self.picture_list=picture_list
		self.videoProperties=videoProperties
		self.t_total=self.total_time()
		self.last_frame=None
		self.last_pixbuf=None
		self.width=-1
		self.height=-1
	
	def total_time(self):
		t_total=0
		for picture in self.picture_list:
			t_total+=int(0.5+float(self.videoProperties.framespersecond)*picture.duration)
			if picture.transition!=None:
				t_total+=int(0.5+float(self.videoProperties.framespersecond)*picture.transition.duration)
		picture=self.picture_list[len(self.picture_list)-1]
		if picture.transition!=None:
			t_total-=int(0.5+float(self.videoProperties.framespersecond)*picture.transition.duration)
		return float(t_total)/float(self.videoProperties.framespersecond)
	
	def get_n_picture(self, n):
		picture=None
		if n<len(self.picture_list):
			picture=self.picture_list[n]
		return picture
	
	def get_picture_by_time(self, time):
		n=0
		t=0.0
		transitionOk=False
		picture=self.get_n_picture(n)
		while picture!=None:
			if t+picture.duration > time:
				break
			t+=picture.duration
			n+=1
			picture2=self.get_n_picture(n)
			if picture2!=None and picture.transition!=None:
				if t+picture.transition.duration > time:
					transitionOk=True
					n-=1
					break
				t+=picture.transition.duration
			picture=picture2
		return picture, n, transitionOk, t
	
	def render_start(self):
		self.last_picture=None
		self.next_picture=None
		self.pixbuf1=None
		self.pixbuf2=None
	
	def render_at_time(self, time):
		picture, n, transitionOk, t=self.get_picture_by_time(time)
		
		pixbuf=None
		if picture==None:
			return pixbuf
		if picture!=self.last_picture:
			if self.last_picture!=None:
				self.last_picture.render_end()
			if self.next_picture!=None:
				self.next_picture.render_end()
				self.next_picture=None
			self.last_picture=picture
			if self.last_picture!=None:
				self.last_picture.render_start()
			self.pixbuf1=None
			self.pixbuf2=None
			#print 'Cambio'
		if transitionOk and self.last_picture!=None and self.last_picture.transition!=None:
			next_picture=self.get_n_picture(n+1)
			if self.next_picture==None or self.next_picture!=next_picture:
				if next_picture==None:
					self.last_picture.render_end()
					if self.next_picture!=None:
						self.next_picture.render_end()
						self.next_picture=None
					self.pixbuf1=None
					self.pixbuf2=None
					return None #Movie is finished
				else:
					#print "Iniciada una transición"
					if self.next_picture!=None:
						self.next_picture.render_end()
					self.next_picture=next_picture
					#print "Se inicia el render de la siguiente imagen"
					self.next_picture.render_start()
					self.last_picture.transition.render_start()
					#print "Se inicia el render de la siguiente imagen en t=0"
					self.pixbuf2=self.next_picture.render(0.0)
					#print "Render de la imagen actual"
					self.pixbuf1=self.last_picture.render(self.last_picture.duration)
					#print "Iniciada una transición"
			#print 'render_transition_at_time='+str(time-t)
			pixbuf=picture.transition.render(time-t, self.pixbuf1, self.pixbuf2)
		elif picture!=None:
			#print 'render_at_time='+str(time-t)
			pixbuf=picture.render(time-t)
		return pixbuf
	
	def render_end(self):
		if self.last_picture!=None:
			self.last_picture.render_end()
			if self.last_picture.transition!=None:
				self.last_picture.transition.render_end()
		self.last_picture=None
		if self.next_picture!=None:
			self.next_picture.render_end()
		self.next_picture=None
		self.pixbuf1=None
		self.pixbuf2=None
		self.videoProperties.width , self.videoProperties.height = self.width, self.height
	
	def save_to_pipe(self, data, pipe):
		#self.last_frame+=data
		#pipe.write(self.last_frame)
		pipe.write(data)
		return True
		
	
	def render_to_play(self, t=0.0):
		#t = time of start of sound
		self.width=self.videoProperties.width
		self.height=self.videoProperties.height
		if self.videoProperties.demoOk:
			self.videoProperties.width , self.videoProperties.height = 72, 56
		#if self.videoProperties.sound_path!='' and os.path.exists( self.videoProperties.sound_path ) and os.path.isfile( self.videoProperties.sound_path ):
		#	command=' ffmpeg -y -f image2pipe -ss 0 -i pipe:.jpg -ss '+str(t)+' -i "'+self.videoProperties.sound_path+'" -t '+str(self.t_total)+' -r '+str(self.videoProperties.framespersecond)+' -sameq -s '+str(width)+'x'+str(height)+' pipe:.mpeg | ffplay pipe:.mpeg'
		#self.render_start()
	
	def render_to_file(self, file_name):
		#t_total tiempo total del vídeo
		if file_name==None:
			return
		#Se recorre la lista de imágenes para generar el render
		#cat *.jpg | ffmpeg -y -f image2pipe -i pipe:.jpg -sameq -s 400x300 -target ntsc-dvd my.mpg
		#cat ex*.png | ffmpeg -y -f image2pipe -img ppm -i - -target ntsc-dvd dvd.mpg
		#cat *.ppm | ffmpeg -y -f imagepipe -img ppm -i - -target ntsc-dvd dvd.mpg
		#cat ex*.png | ffmpeg -y -f image2pipe -vcodec mjpeg -i - -target ntsc-dvd dvd.mpg
		#cat ex*.png | ffmpeg -y -f imagepipe -vcodec mjpeg -i - -target ntsc-dvd dvd.mpg
		#cat *.png | ffmpeg -y -f image2pipe -i pipe:.png -target ntsc-dvd my.mpg
		#cat *.jpg | ffmpeg -y -f image2pipe -i pipe:.jpg -target ntsc-dvd my.mpg
		
		command='ffmpeg -y -f image2pipe -i pipe:.jpg -t '+str(self.t_total)+' -r '+str(self.videoProperties.framespersecond)+' -sameq -s '+str(self.videoProperties.width)+'x'+str(self.videoProperties.height)+'  "'+file_name+'"'
		#command='ffplay -f image2pipe pipe:.jpg -s '+str(self.videoProperties.width)+'x'+str(self.videoProperties.height)
		if self.videoProperties.sound_path!='' and os.path.exists( self.videoProperties.sound_path ) and os.path.isfile( self.videoProperties.sound_path ):
			command=' ffmpeg -y -f image2pipe -i pipe:.jpg -i "'+self.videoProperties.sound_path+'" -t '+str(self.t_total)+' -r '+str(self.videoProperties.framespersecond)+' -vframes '+str(int(self.videoProperties.framespersecond*self.t_total))+' -sameq -s '+str(self.videoProperties.width)+'x'+str(self.videoProperties.height)+' "'+file_name+'"'
		self.render_start()
		self.render_to_command(command)
		self.render_end()
		#if self.videoProperties.sound_path!='' and os.path.exists( self.videoProperties.sound_path ) and os.path.isfile( self.videoProperties.sound_path ):
		#	command=' ffmpeg -i "'+self.videoProperties.sound_path+'" -i "'+file_name+'" "'+file_name+'-sound.mpeg"'
		#	print command
		#	os.system(command)
		#	command=' mv -f "'+file_name+'-sound.mpeg" "'+file_name+'"'
		#	print command
		#	os.system(command)
	
	def render_to_command(self, command):
		print command
		args = shlex.split(command)
		print args
		ffmpeg=subprocess.Popen(args, shell=False, bufsize=2, stdin=subprocess.PIPE).stdin
		self.render_to_pipe(ffmpeg)
		ffmpeg.close()
	
	def render_to_pipe(self, pipe):
		elapsed_time=os.times()[0]
		i=0
		t=0.0
		pixbuf=0
		self.last_pixbuf=None
		pixbuf=self.render_at_time(t)
		while pixbuf!=None:
			self.last_frame=''
			if pipe!=None:
				pixbuf.save_to_callback(self.save_to_pipe, "jpeg", {"quality":"100"}, pipe)

			if pipe!=None and pipe.closed:
				break
			#if pipe!=None:
			#	pipe.write(self.last_frame)
			i+=1
			t=float(i)/float(self.videoProperties.framespersecond)
			#print "Render t="+str(t)
			pixbuf=self.render_at_time(t)
		print 'Render finish'
		print 'elapsed time='+str(os.times()[0]-elapsed_time)
		pipe.close()



